import ast
import csv
import os

import matplotlib.pyplot as plt
import numpy as np


# 有4种实体: subreddit相当于贴吧, submission相当于帖子, comment相当于帖子下的评论, interaction相当于用户点赞, 回复评论
# 三种实体的id名字映射为: subreddit->subreddit_id, submission->link_id, comment->comment_id

# 帖子
class submission:
    def __init__(self, subreddit_id, title, link_id, tokens):
        super(submission, self).__init__()
        self.subreddit_id: int = subreddit_id  # id of the subreddit that this submission belongs to.
        self.title: str = title
        self.link_id: int = link_id  # id of this submission.
        self.tokens: list = tokens  # list of str. words extracted from the title of the submission.

    def __str__(self):
        return "subreddit_id: {}, link_id: {}, title: {}".format(self.subreddit_id, self.link_id, self.title)


# 一条评论
class comment:
    def __init__(self, author_id: int, link_id: int, subreddit_id: int,
                 body: str, created_utc: int, score: int, comment_id: int, tokens: list):
        super(comment, self).__init__()
        self.author_id: int = author_id
        self.link_id: int = link_id
        self.subreddit_id: int = subreddit_id
        self.body: str = body
        self.created_utc: int = created_utc  # the timestamp when the comment is created. the time zone is utc(+0:00).
        self.score: int = score  # upvote - downvote
        self.comment_id: int = comment_id
        self.tokens: list = tokens  # list of str. tokens(words) extracted from the body.


class interaction:
    """
    代表author与某个comment进行的交互, 比如回复评论

    author: ##与lv0_id所指示的评论所交互的用户##
    link_id: 这条交互所属于的帖子(submission)
    comment_id: 用户所交互的评论
    comment_author_id: 用户所交互的评论的作者
    counts: 用户交互该条评论的次数(有可能是他们在讨论，所以这个次数意义不算大)
    label: 标签，目前只保存了正例，所以都是1. 此处不收录
    """
    def __init__(self, author_id, link_id, comment_id, comment_author_id, counts):
        self.author_id: int = author_id
        self.link_id: int = link_id
        self.comment_id: int = comment_id
        self.comment_author_id: int = comment_author_id
        self.counts: int = counts


# 读取用户对帖子的一楼评论
def read_comments(project_root):
    """
    read comments file.
    :return: dict of comments. key: comment_id, value: comment
    """
    comments_file = os.path.join(project_root, "data/reddit_small/reddit_comments.csv")
    comments = dict()
    dup_count = 0
    with open(comments_file, "r") as csv_file:
        reader = csv.reader(csv_file)
        for i, item in enumerate(reader):
            if i == 0:
                feature_num = len(item)
                print("titles", item)
                continue

            # read a comment.
            comment_id: int = int(item[6])
            if comment_id in comments:
                dup_count += 1

            comments[comment_id] = comment(int(item[0]), int(item[1]), int(item[2]), item[3],
                                           int(item[4]), int(item[5]), int(item[6]), ast.literal_eval(item[7]))
    return comments


# 读取帖子文件
def read_submissions(project_root):
    submission_file = os.path.join(project_root, "data/reddit_small/reddit_submission.csv")
    submissions = dict()
    dup_count = 0  # duplicate items count.
    with open(submission_file, "r") as csv_file:
        reader = csv.reader(csv_file)
        for i, item in enumerate(reader):
            if i == 0:
                continue

            # read a submission
            link_id = int(item[3])
            if link_id in submissions:
                dup_count += 1
            else:
                # item[0]是author_id, 由于大量的贴吧author_id为-1, 无需记录.
                submissions[link_id] = submission(int(item[1]), item[2], int(item[3]), ast.literal_eval(item[4]))

    return submissions, dup_count


def read_interactions(project_root, flag):
    """
    :param project_root: 项目根目录
    :param flag: train, test, or validtion
    :return: interactions
    """
    valid_flags = ["train", "test", "validation"]
    if flag not in valid_flags:
        raise Exception("flag must be one of {}".format(valid_flags))

    interaction_file = os.path.join(project_root, "data/reddit_small/reddit_{}.csv".format(flag))
    interactions = dict()
    interaction_count = 0
    with open(interaction_file, "r") as csv_file:
        reader = csv.reader(csv_file)

        for i, item in enumerate(reader):
            if i == 0:
                continue

            # read an interaction.
            author_id = int(item[0])
            comment_id = int(item[2])

            interaction_tuple = (author_id, comment_id)

            if author_id not in interactions:
                interactions[author_id] = dict()
            if comment_id not in interactions[author_id]:
                interaction_count += 1
                interactions[author_id][comment_id] = interaction(int(item[0]), int(item[1]),
                                                              int(item[2]), int(item[3]), int(item[4]))
    return interactions, interaction_count


if __name__ == '__main__':
    from conf import ROOT
    read_comments(ROOT)

    submissions, dup_count = read_submissions(ROOT)
    print("重复与不重复的帖子数", dup_count, len(submissions))

    comments = read_comments(ROOT)

    # Interactions.
    interactions, dup_count = read_interactions(ROOT, "train")
    print("重复与不重复的交互数", dup_count, len(interactions))

    # Count user comments.
    user_comments = dict()
    for comment_id, comment in comments.items():
        if comment.author_id not in user_comments:
            user_comments[comment.author_id] = [comment]
        else:
            user_comments[comment.author_id].append(comment)

    # 计算发了n条评论的用户有多少人.
    comment_size = dict()
    for user_id, comments in user_comments.items():
        if len(comments) not in comment_size:
            comment_size[len(comments)] = 1
        else:
            comment_size[len(comments)] += 1

    count_no_comment = 0
    uids = [uid for uid in interactions.keys()]
    for uid in uids:
        if uid not in user_comments:
            count_no_comment += 1
    print("与评论有交互的用户数为{}, 其中没有发表过评论的用户数为{}".format(len(uids), count_no_comment))

    # 将发布评论条数分布显示出来
    plt.figure()
    xs = []
    ys = []
    for size, num in comment_size.items():
        xs.append(size)
        ys.append(num)
    plt.scatter(xs, ys)
    plt.xlim([0, 30])
    plt.show()

